#include "render_system2d.h"
#include <GL/glew.h>
#include "engine/renderer/mesh/particle_system.h"
#include "engine/core/logging.h"

namespace kanon
{
    RenderSystem2d::RenderSystem2d(uint32_t width, uint32_t height)
    {
        sprite_renderer = std::make_shared<SpriteRenderer>();
        particle_renderer = std::make_shared<ParticleRenderer>();
        elipse_renderer = std::make_shared<ElipseRenderer>();
        polygon_renderer = std::make_shared<PolygonRenderer>();
        screenspace_renderer = std::make_shared<ScreenspaceRenderer>();

        framebuffer = std::make_shared<FrameBuffer>();
        framebuffer->Init(width, height, 1, true);

        this->width = width;
        this->height = height;
    }

    void RenderSystem2d::Begin()
    {
        framebuffer->Bind();

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // glEnable(GL_DEPTH_TEST);
    }

    void RenderSystem2d::End()
    {
        framebuffer->Unbind();
        // do frame rendering.
        uint32_t texture_id = framebuffer->GetColorAttachment(0);
        screenspace_renderer->Render(texture_id);
    }

    void RenderSystem2d::SetCamera2D(const std::shared_ptr<Camera2d>& cam)
    {
        sprite_renderer->SetCamera(cam);
        particle_renderer->SetCamera(cam);
        elipse_renderer->SetCamera(cam);
        polygon_renderer->SetCamera(cam);
    }

    void RenderSystem2d::Render(const std::shared_ptr<ActorSystem>& actor_system)
    {
        RenderSprites(actor_system);
        RenderParticleSystem(actor_system);
        RenderCircles(actor_system);
    }

    void RenderSystem2d::RenderSprites(const std::shared_ptr<ActorSystem>& actor_system)
    {
        sprite_renderer->Begin();
        for (auto& act : actor_system->actors)
        {
            if (!act->HasComponent<SpriteMeshComponent>())
                continue;
            if (!act->HasComponent<Transform2DComponent>())
                continue;
            if (!act->HasComponent<Render2DComponent>())
                continue;

            auto& mesh = act->GetComponent<SpriteMeshComponent>();
            auto& t = act->GetComponent<Transform2DComponent>();
            auto& m = act->GetComponent<Render2DComponent>();
            SpriteQuad sprite;
            sprite.pos = t.position;
            sprite.size = mesh.size;
            sprite.color = m.color;
            sprite.texture = m.texture;

            sprite_renderer->Submit(sprite);
        }
        sprite_renderer->End();
    }

    void RenderSystem2d::RenderParticleSystem(const std::shared_ptr<ActorSystem>& actor_system)
    {
        particle_renderer->Begin();
        for (auto& act : actor_system->actors)
        {
            if (!act->HasComponent<ParticleMeshComponent>())
                continue;
            if (!act->HasComponent<Transform2DComponent>())
                continue;
            if (!act->HasComponent<ParticleRenderComponent>())
                continue;

            auto& mesh = act->GetComponent<ParticleMeshComponent>();
            auto& t = act->GetComponent<Transform2DComponent>();
            auto& r = act->GetComponent<ParticleRenderComponent>();
            
            particle_renderer->Render(mesh.particles, r.color, t.position);
        }
        particle_renderer->End();
    }

    void RenderSystem2d::RenderCircles(const std::shared_ptr<ActorSystem>& actor_system)
    {
        elipse_renderer->Begin();
        for (auto& act : actor_system->actors)
        {
            if (!act->HasComponent<CircleMeshComponent>())
                continue;
            if (!act->HasComponent<Transform2DComponent>())
                continue;
            if (!act->HasComponent<CircleRenderComponent>())
                continue;

            auto& mesh = act->GetComponent<CircleMeshComponent>();
            auto& t = act->GetComponent<Transform2DComponent>();
            auto& r = act->GetComponent<CircleRenderComponent>();

            Elipse e;
            e.center = t.position;
            e.radius = mesh.radius;
            e.color = r.color;
            elipse_renderer->Render(e);
        }
        elipse_renderer->End();
    }

    void RenderSystem2d::RenderSelected(const std::shared_ptr<ActorSystem>& actor_system, int32_t index)
    {
        auto& actor = actor_system->actors[index];
        if (!actor->HasComponent<Collider2DComponent>())
            return;
        glm::vec4 color = { 0.2f, 0.3f, 0.7f, 1.0f };
        auto& c = actor->GetComponent<Collider2DComponent>();
        std::vector<glm::vec2> lines = {
            { c.bbox.x, c.bbox.y },
            { c.bbox.z, c.bbox.y },
            { c.bbox.z, c.bbox.w },
            { c.bbox.x, c.bbox.w },
        };
        polygon_renderer->Begin();
        polygon_renderer->SetLineWidth(2.0f);
        polygon_renderer->Render(lines, color, true);
        polygon_renderer->End();
    }
}
